﻿using System;
using LogX.Logging;
using TUtils.BasicHelper.Logging;

namespace MMessaging.MessagingEx.Common
{
	/// <summary>
	/// Repräsentiert den Verarbeitungsvorgang einer Message ("OriginalMessage").
	/// </summary>
	/// <typeparam name="MESSAGETYPE"></typeparam>
	public interface IMTask<MESSAGETYPE>
		where MESSAGETYPE : class
	{
		/// <summary>
		/// Die Message, dessen Verarbeitung die Aufgabe dieses Verarbeitungsvorgangs ist.
		/// </summary>
		MESSAGETYPE OriginalMessage { get; }

		/// <summary>
		/// Bis zum Verarbeitungsende der "OriginalMessage" können viele andere Messages 
		/// empfangen werden. "CurrentMessage" ist die aktuell verarbeitete Message.
		/// Zu Beginn des Verarbeitungsprozesses ist CurrentMessage == OriginalMessage.
		/// CurrentMessage verändert sich nicht, bis man WaitOnMessageXXX(..) aufruft.
		/// Achtung ! CurrentMessage kann null sein.
		/// </summary>
		MESSAGETYPE CurrentMessage { get; }

		/// <summary>
		/// Blockiert, bis die übergebene Bedingung erfüllt ist oder der Thread gecancelt wird.
		/// ACHTUNG ! Diese Methode darf nicht aufgerufen werden, wenn der aufrufende Thread noch
		/// ein Synchronisationobjekt gesperrt hat.
		/// </summary>
		/// <remarks>
		/// Folgendes ist verboten:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///		WaitOnMessage(msg=>msg is MyMessage);
		///		...
		/// }
		/// </code>
		/// Das könnte zu einem Deadlock führen, wenn ein anderer Thread das Objekt ebenfalls 
		/// sperren möchte, während dieser Thread auf die Erfüllung der Bedingung wartet.
		/// Erlaubt ist hingegen:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///	}
		///	
		///	WaitOnMessage(msg=>msg is MyMessage);
		///	
		/// lock(syncObj)
		/// {
		///		...
		///	}
		/// </code>
		/// </remarks>
		/// <param name="condition">
		/// Dieser Delegate wird vom MessageHandlerThread direkt aufgerufen !
		/// MESSAGETYPE kann null sein !
		/// </param>
		/// <param name="logText">
		/// Dieser Text wird in Logging Ausgaben genutzt.
		/// </param>
		/// <returns>
		/// false, wenn der Thread terminiert wird.
		/// </returns>
		bool WaitOnMessage(string logText, Func<MESSAGETYPE, bool> condition);

		/// <summary>
		/// Blockiert, bis die übergebene Bedingung erfüllt ist, der Thread gecancelt wird oder
		/// der geg. Timeout abläuft.
		/// ACHTUNG ! Diese Methode darf nicht aufgerufen werden, wenn der aufrufende Thread noch
		/// ein Synchronisationobjekt gesperrt hat.
		/// </summary>
		/// <remarks>
		/// Folgendes ist verboten:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///		WaitOnMessage(msg=>msg is MyMessage);
		///		...
		/// }
		/// </code>
		/// Das könnte zu einem Deadlock führen, wenn ein anderer Thread das Objekt ebenfalls 
		/// sperren möchte, während dieser Thread auf die Erfüllung der Bedingung wartet.
		/// Erlaubt ist hingegen:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///	}
		///	
		///	WaitOnMessage(msg=>msg is MyMessage);
		///	
		/// lock(syncObj)
		/// {
		///		...
		///	}
		/// </code>
		/// </remarks>
		/// <param name="timeoutMilliseconds">
		/// timeout in Millisekunden.
		/// </param>
		/// <param name="condition">
		/// Dieser Delegate wird vom MessageHandlerThread direkt aufgerufen !
		/// MESSAGETYPE kann null sein !
		/// </param>
		/// <param name="logText">
		/// Dieser Text wird in Logging Ausgaben genutzt.
		/// </param>
		/// <returns>
		/// SUCCEEDED, TIMEOUT, CANCELED
		/// </returns>
		MWaitResult WaitOnMessage(string logText, int timeoutMilliseconds, Func<MESSAGETYPE, bool> condition);

		/// <summary>
		/// Blockiert den aufrufenden Thread, bis die übergebene Bedingung erfüllt ist, 
		/// der Thread gecancelt wird oder der geg. Timeout abläuft. 
		/// Im Fehlerfall oder beim von außen erzwungenen Abbruch wirft "WaitOnMessageOrException(..)"
		/// eine MWaitException.
		/// </summary>
		/// <remarks>
		/// ACHTUNG ! Diese Methode darf nicht aufgerufen werden, wenn der aufrufende Thread noch
		/// ein Synchronisationobjekt gesperrt hat.
		/// Folgendes ist verboten:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///		WaitOnMessage(msg=>msg is MyMessage);
		///		...
		/// }
		/// </code>
		/// Das könnte zu einem Deadlock führen, wenn ein anderer Thread das Objekt ebenfalls 
		/// sperren möchte, während dieser Thread auf die Erfüllung der Bedingung wartet.
		/// Erlaubt ist hingegen:
		/// <code>
		/// lock(syncObj)
		/// {
		///		...
		///	}
		///	
		///	WaitOnMessage(msg=>msg is MyMessage);
		///	
		/// lock(syncObj)
		/// {
		///		...
		///	}
		/// </code>
		/// </remarks>
		/// <param name="timeoutMilliseconds">
		/// timeout in Millisekunden.
		/// </param>
		/// <param name="logText">
		/// Dieser Text wird in Logging Ausgaben genutzt.
		/// </param>
		/// <param name="condition">
		/// Dieser Delegate wird vom MessageHandlerThread direkt aufgerufen !
		/// MESSAGETYPE kann null sein !
		/// </param>
		/// <exception cref="MWaitException">
		/// wenn der thread gecancelt wird oder der Timeout abläuft.
		/// </exception>
		void WaitOnMessageWithTimeoutException(string logText, int timeoutMilliseconds, Func<MESSAGETYPE, bool> condition);

		/// <summary>
		/// Blockiert den aufrufenden Thread, bis die angegebene Zeit überschritten ist oder
		/// der Thread gecancelt wird. 
		/// Im Fehlerfall oder beim von außen erzwungenen Abbruch wirft "SleepWithException(..)"
		/// eine MWaitException.
		/// ACHTUNG ! Diese Methode darf nicht aufgerufen werden, wenn der aufrufende Thread noch
		/// ein Synchronisationobjekt gesperrt hat.
		/// </summary>
		/// <param name="timeoutMilliseconds"></param>
		/// <exception cref="MWaitException"></exception>
		void SleepWithException(int timeoutMilliseconds);
	}
}